CPS222 Lecture: Pointers and References in C++         Last revised 1/31/15

Objectives:

1. To introduce C++ pointers
2. To introduce dynamic storage allocation/deallocation in C++.
3. To introduce C++ references

Materials:

1. C++/Java comparison handout

I. Pointers 
-  --------

   A. Some notes on computer memory and variables

      1. On almost all computers, memory is structured as a sequence of bytes, each
         of which has an address.
     
         Example: A computer with 1 GB of mememory would a memory with addresses
                  ranging from 0 .. 1,073,741,823.
              
      2. If a value requires more than one byte to store (as almost all do), it is
         given the appropriate number of successive memory locations.
     
         Example: If an int requires 4 bytes, then it might be allocated - say -
                  bytes 1000, 1001, 1002, 1003
              
                  The first of these is typically regarded as the address of the 
                  item - e.g. the int referred to above would have address 1000
              
      3. A variable is a symbolic name for a location in memory - so we can speak
         of the address of a variable.  Storage is allocated (and this location is 
         bound) in one of three ways, depending on how the variable is declared.
     
         a. A static variable is permanently allocated the appropriate amount of
            storage.
       
         b. For a local variable (or parameter), storage is allocated when the
            function in which it is declared is entered, and deallocated when it
            is terminated.  The binding between the variable name and the address
            is in effect only while the function is active.
       
            Note: In the case of recursive functions, this may mean that the same
                  name refers to several different memory locations - but there is
                  no ambiguity because only one invocation is current at any one time.
             
          c. For a dynamic variable, storage is allocated by new and deallocated by
             delete.
       
       4. In both C and C++, the operator & is the "address of" operator, and can 
          be applied to any variable to give the address in memory that variable is 
          a name for
     
          Example: If int foo; results in the variable foo being associated with
                   locations 1000-1003 in memory, then & foo is 1000.
       
   B. Pointers in C++

      - For examples, we will assume the following class declaration
     
           class Demo { int _i; double _d; };

      1. Pointers are found in many progamming languages.  They entered C++ from C.
   
      2. A pointer variable (or field of a class) is declared in C/C++ by a 
         declaration of the form
     
         <Type> * <name>
     
         e.g. int * p;  // p is a pointer to an int
              Demo * p; // p is a pointer to a Demo object
   
      3. A pointer variable is a symbolic name for a location in memory that holds
         the address in memory of _another_ item.
     
         Example: Demo * p = new Demo() might result in something like this
     
           ------    ------
         p |   o|--> | _i |
           ------    | _d |
                     |    |
                     ------
                 
         (A pointer variable can refer to no object, in which case it has the
          value 0 - symbolically NULL)
      
       4. A pointer variable can be used to refer to itself or the "pointee" - if
          there is one.
     
          a. A usage of the variable name by itself refers to the pointER:
             Pointers are subject only to the following operations: assignment,
             comparison for equality (==, != - same object), increment/decrement
             ++, -- (Done in steps of declared pointEE type size)
       
             Example: 
          
             Demo * p, * q;
             ...
             q = p; // makes q refer to the same object p does
             if (p == NULL) // tests whether there is actually an object that p points to 

          b. It can be dereferenced to refer to the pointEE:
     
             Example: In the above, *p is a Demo object, (*p)._i is the _i field of 
                      this object, etc.  
                
          c. In C++, p -> _i and (*p)._i are equivalent, but the former is 
             preferred for readability
            
   C. Go over section 11 in handout
   
II. Storage Allocation in C++
    ------- ---------- -- ---
    
    Go over section 12 in handout
     
III. References
---  ----------

   A. References in C++

      1. References are a new feature in C++ - not found in C
   
      2. A reference variable (or field of a class) is declared in C/C++ by a 
         declaration of the form
     
         <Type> & <name>
     
         e.g. int & p;  // p is a reference to an int
              Demo & p; // p is a reference to a Demo object
          
      3. A reference variable is implemented in exactly the same way as a pointer
         variable is (i.e. it is the symbolic name of a location in memory that
         holds the address in memory of another item).  However, while the
         implementation is the same, the way the compiler handles a reference
         variable is different.
     
         a. A reference is immutable.  When it is created, it must be assigned what
            it is to refer to, and it cannot thereafter be changed.
       
         b. All uses of a reference variable affect the referEE - not the reference.
            (There is therefore no need for an explicit dereferencing operation 
             like * or -> with pointers)
       
      4. In fact, a reference is an alias - another name for the same thing as the
         item it refers to.  Anything use of the reference has exactly the same
         meaning as doing the same thing with the thing it refers to.
       
         Examples: If Clark Kent flies to London, Superman is in England.
                   If Superman is exposed to kryptonite, Clark Kent dies
               
      5. One of the key uses for references in C++ is for something known as "call 
         by reference".
     
         a. Consider the matter of passing parameters to a function.  The 
            conventional way of handling this is something known as "call by 
            value": the function is given a COPY of the actual parameter.
       
         b. A strength of this is that it allows the parameter to be a variable,
            a constant, or even an expression.
         
         c. There are two weaknesses, however
       
            i. Any changes made by the function are not visible to the caller,
               since they are made to a copy, not to the original.
           
               (Contrast making a photocopy of a book from the library as opposed
               to checking out the actual book - what happens in each case if you
               write on what you have?)

           ii. If the actual parameter is large, there is a lot of overhead needed
               to copy it.
           
          iii. For these reasons, one sometimes sees C functions in which a pointer
               is passed, rather than an actual value 
            
               - Example:
           
                   void increment(int n) { n ++; }
                   ...
                   int i = 3;
                   increment(i);
                   cout << i << endl;  // writes 3
               
                   vs 
               
                   void increment(int * n) { (*n) ++; }
                   ...
                   int i = 3;
                   increment(& i);
                   cout << i << endl;  // writes 4
               
                   The former writes 3, but the latter writes 4.  Why?
                
               - Another example:
            
                   void something(LargeClass c)
                   { fields of c referred to by c. }
                   ...
                   LargeClass x;
                   something(x); // Copies entire LargeClass object
                
                   vs
                
                   void something(LargeClass * c)
                   { fields of c referred to using (*c). or c -> }
                   ...
                   LargeClass x;
                   something(& x); // Copies only an address
                
           iv. With a C++ reference, these could be written as
           
                  void increment(int & n) { n ++; }
                  ...
                  int i = 3;
                  increment(i);
                  cout << i << endl; // writes 4 - presumably as desired 
               
                  void something(LargeClass & c)
                  { fields of c referred to by c. }
                  ...
                  LargeClass x;
                  something(x);  // Copies only an address
        
                 (In both cases, same semantics as with a pointer, but much cleaner 
                syntax.  In some cases (e.g. operator overloading) pointer syntax
                 becomes unusable.) 

   B. Go over section 13 in handout
   
   C. Comparison to Java

      1. Java has what it calls references, which are like both pointers and
         references in C++ in different ways.
     
         But note that whether a variable is a reference is solely determined by
         its type (so called "value types" and "reference types").  One cannot
         have a reference to an int or a variable of class type that is not a
         reference.
       
      2. A Java reference acts like a C++ pointer for purposes of assignment and
         comparison, but like a C++ reference for all other purposes!